<?php
namespace Utils;

use think\Session;
/**
 * CSRF Token生成与检验类
 */
class CSRFToken {
    /**
     * 过期时间
     * @var integer */
    private $expire = 3600;

    public function setExpire($expireTime){
        $this->expire = $expireTime;
    }

    /**
     * 获取CSRF Token
     * @return string CSRF Token
     */
    public function get(){
        $token = $this->generateToken();
        $this->pushSession($token);
        return $token;
    }

    /**
     * 检验CSRF Token
     * @param string $token - CSRF Token
     * @return bool 验证结果
     */
    public function check($token){
        if(Session::has('csrf_token')){
            $tokenStorage = Session::get('csrf_token');
            $tokenStorage = $this->fliteExpired($tokenStorage);
            Session::set('csrf_token', $tokenStorage);
            foreach($tokenStorage as $key => $one){
                if($one['token'] === $token){
                    unset($tokenStorage[$key]); //删除已经验证通过的
                    return true;
                }
            }
            return false;
        } else {
            return false;
        }
    }

    /**
     * 删除指定CSRF Token
     * @param [type] $token - CSRF Token
     * @return bool 结果
     */
    public function remove($token){
        if(Session::has('csrf_token')){
            $tokenStorage = Session::get('csrf_token');
            $tokenStorage = $this->fliteExpired($tokenStorage);
            foreach($tokenStorage as $key => $one){
                if($one['token'] === $token){
                    unset($tokenStorage[$key]); //删除已经验证通过的
                    Session::set('csrf_token', $tokenStorage);
                    return true;
                }
            }
            Session::set('csrf_token', $tokenStorage);
            return false;
        } else {
            return false;
        }
    }

    private function pushSession($token){
        if(Session::has('csrf_token')){
            $tokenStorage = Session::get('csrf_token');
            $tokenStorage = $this->fliteExpired($tokenStorage);
        } else {
            $tokenStorage = [];
        }
        $tokenStorage[] = [
            'expire' => time() + $this->expire,
            'token' => $token,
        ];
        Session::set('csrf_token', $tokenStorage);
        return true;
    }

    private function fliteExpired($data){
        $response = [];
        $currentTime = time();
        foreach($data as $one){
            if($one['expire'] > time()){
                $response[] = $one;
            }
        }
        return $response;
    }

    private function generateToken(){
        return md5(uniqid(md5(microtime(true)), true));
    }
}